import java.rmi.* ; 
import java.rmi.server.UnicastRemoteObject ;
import java.net.MalformedURLException ; 
import java.util.Hashtable;
import java.util.*;
import javax.media.*;

import java.rmi.RemoteException ;

public class Client_Impl extends UnicastRemoteObject implements Client_Itf 
{
	int id; //sert de capacite
	Hashtable listeVoisins = new Hashtable();
	int idPremierEmetteurJeton;
	Serveur_Itf s;
	String ip;
	String file;
	String port;
	
	class ThreadServeurStreaming extends Thread 
	{
		  ThreadServeurStreaming() 
		  {
		  }

		  public void run() 
		  {
		  		
				System.out.println("lancement serveur streaming");
				System.out.println("file " + file);
				System.out.println("ip " + ip);
				System.out.println("port " + port);
				// Create a video transmit object with the specified params.
				VideoTransmit vt = new VideoTransmit(new MediaLocator(file), ip, port);
				System.out.println("new VideoTransmit");
		
				// Start the transmission
				System.out.println("avant vt.start()");
				String result = vt.start();
				System.out.println("après vt.start()");

				// result will be non-null if there was an error. The return
				// value is a String describing the possible error. Print it.
				if (result != null) 
				{
					System.err.println("Error : " + result);
					System.exit(0);
				}
				System.out.println("result == null");

				System.err.println("Start transmission for 60 seconds...");
	
				// Transmit for 60 seconds and then close the processor
				// This is a safeguard when using a capture data source
				// so that the capture device will be properly released
				// before quitting.
				// The right thing to do would be to have a GUI with a
				// "Stop" button that would call stop on VideoTransmit
				try 
				{
					Thread.currentThread().sleep(60000);
				} 
				catch (InterruptedException ie) 
				{
				}
				System.out.println("try");

				// Stop the transmission
				vt.stop();
				System.out.println("vt.stop();");

				System.err.println("...transmission ended.");
	
				System.exit(0);
	
		  }
	}
	
	public Client_Impl (String adServeur, String adip, String adport, String adfile) throws RemoteException 
	{
		try 
		{
			s =(Serveur_Itf) Naming.lookup("rmi://"+ adServeur +"/Serveur");

			id = s.addList(this);
			System.out.println("je suis le client " + id);
			
			s.getVoisins(id);
			
			ip = adip;
			file = adfile;
			port = adport;
		}
		catch (NotBoundException re) 
		{ 
			System.out.println(re); 
		}
		catch (RemoteException re) 
		{ 
			System.out.println(re); 
		}
		catch (MalformedURLException e) 
		{ 
			System.out.println(e); 
		}
	}

	public void addVoisinConnection(Client_Itf cNouveauVoisin, int idNouveauVoisin) throws RemoteException
	{
		try
		{	
			String cle = "" + idNouveauVoisin;
			listeVoisins.put(cle, cNouveauVoisin);
			System.out.println("Nouveau voisin : " + idNouveauVoisin);

			cNouveauVoisin.addVoisin(this, id);
		}
		catch (NullPointerException re) 
		{ 
			//System.out.println(re); 
		}
	}
	
	public void addVoisin(Client_Itf cNouveauConnecte, int idNouveauConnecte) throws RemoteException
	{
		String cle = "" + idNouveauConnecte;
		listeVoisins.put(cle, cNouveauConnecte);
		System.out.println("Nouveau voisin : " + idNouveauConnecte);
	}
	
	public void election(int idEmetteur, int capacite, int idCapacite, Hashtable liste, int idInit, int type, String url) throws RemoteException
	{	
		if(liste.containsKey("" + id)) 					// si on est dans la liste, cela signifie que l'on a déjà reçu le jeton
		{
			
			int nextVoisin = trouverVoisin(liste);
			
			if(nextVoisin != -1) 						// si on a encore un voisin qui n'a pas recu le jeton
			{
				((Client_Itf) listeVoisins.get("" + nextVoisin)).election(id, capacite, idCapacite, liste, idInit, type, url);	// on lui envoie
			}
			else 										// s'il n'y en a pas, on renvoie à celui qui nous l'a envoyé
			{
				if(id == idInit) 						// si le jeton est au point de départ
				{
					if(type == 0)						// si election
					{
						System.out.println("Election fin, début information");
						System.out.println("J'ai élu "+ idCapacite +"!");
						this.election(id, 0, idCapacite,new Hashtable(), id, 1, url);	// 1 : information -> informer le mec élu qu'il est élu
					}
					else
					{
						System.out.println("Je récupère l'ip et le port du client élu sur le serveur");
						String session = s.iReceive() + "/60"; //<ip>/<port>/<ttl>
						System.out.println("\tsession : " + session);
						String [] sessions =new String[1];
						sessions[0] = session;
		  			this.clientStreaming(sessions);						
					}
				}
				else									// sinon on l'envoie au précédent
				{
					((Client_Itf) listeVoisins.get("" + idPremierEmetteurJeton)).election(id, capacite, idCapacite, liste, idInit, type, url);
				}
			}
			
			
		}
		else 													// sinon c'est la premiere fois qu'on reçoit le jeton
		{
			
			
			idPremierEmetteurJeton = idEmetteur;
			liste.put(""+id,this);								// on s'ajoute dans la liste
			
			if(type == 0)										// si election
			{
				capacite = capacite > id ? capacite : id; 		// capacite max
				idCapacite = capacite > id ? idCapacite : id;	// id de la capacite max
			}
			else												// sinon information
			{
				if(idCapacite == id)
				{
					System.out.println("J'ai été élu par " + idInit + " !");
					System.out.println("J'envois mon ip et mon n° de port au serveur");
					System.out.println("\tip : " + ip + " / port : " + port);
					s.iSend(ip,port);		
					file = url;			
					ThreadServeurStreaming p = new ThreadServeurStreaming();
					p.start();
				}

				if(id == idInit)
				{
					System.out.println("troll");
				}
				if(idCapacite != id && id != idInit)
				{
					System.out.println("Je sais que " + idInit + " a élu "+ idCapacite +"!");
				}

			}
		
			int nextVoisin = trouverVoisin(liste);
			
			if(nextVoisin != -1) 								// si on a encore un voisin qui n'a pas recu le jeton
			{
				((Client_Itf) listeVoisins.get("" + nextVoisin)).election(id, capacite, idCapacite, liste, idInit, type, url);	// on lui envoie
			}
			else 												// s'il n'y en a pas, on renvoit à celui qui nous l'a envoyé
			{
				if(id == idInit)
				{
					this.election(id, capacite, idCapacite, liste, idInit, type, url);
				}
				else
				{
					((Client_Itf) listeVoisins.get("" + idPremierEmetteurJeton)).election(id, capacite, idCapacite, liste, idInit, type, url);
				}
			}
		}
	}
	
	public void messageAll(int idEmetteur, Hashtable liste, int idInit, String message) throws RemoteException
	{	
		if(liste.containsKey("" + id)) 					// si on est dans la liste, cela signifie que l'on a déjà reçu le jeton
		{
			
			int nextVoisin = trouverVoisin(liste);
			
			if(nextVoisin != -1) 						// si on a encore un voisin qui n'a pas recu le jeton
			{
				((Client_Itf) listeVoisins.get("" + nextVoisin)).messageAll(id, liste, idInit,message);	// on lui envoie
			}
			else 										// s'il n'y en a pas, on renvoie à celui qui nous l'a envoyé
			{
				if(id == idInit) 						// si le jeton est au point de départ
				{
					//fin de transmission
					System.out.println("Message propagé");
				}
				else									// sinon on l'envoie au précédent
				{
					((Client_Itf) listeVoisins.get("" + idPremierEmetteurJeton)).messageAll(id, liste, idInit,message);
				}
			}
			
			
		}
		else 													// sinon c'est la premiere fois qu'on reçoit le jeton
		{
			
			
			idPremierEmetteurJeton = idEmetteur;
			liste.put(""+id,this);								// on s'ajoute dans la liste
			if(id != idInit)
			{
				System.out.println("Message reçu du client " + idInit + " : " + message);
			}
			
			int nextVoisin = trouverVoisin(liste);
			
			if(nextVoisin != -1) 								// si on a encore un voisin qui n'a pas recu le jeton
			{
				((Client_Itf) listeVoisins.get("" + nextVoisin)).messageAll(id, liste, idInit,message);	// on lui envoie
			}
			else 												// s'il n'y en a pas, on renvoit à celui qui nous l'a envoyé
			{
				if(id == idInit)
				{
					this.messageAll(id, liste, idInit,message);
				}
				else
				{
					((Client_Itf) listeVoisins.get("" + idPremierEmetteurJeton)).messageAll(id, liste, idInit,message);
				}
			}
		}
	}
	
	public int trouverVoisin(Hashtable liste) throws RemoteException
	{
		boolean trouve = false;
		int retour=-1;
		
		for(Enumeration e = listeVoisins.keys(); e.hasMoreElements();)
		{
			String cle = (String)e.nextElement();
			
			if(!trouve)
			{
				if(!liste.containsKey(cle))
				{
					trouve = true;
					retour = Integer.parseInt(cle);
				}
			} 
		}
		return retour;
	}
	
	private void clientStreaming (String[] sessions)
	{
		System.out.println("lancement client streaming");
		AVReceive2 avReceive = new AVReceive2(sessions);
		System.out.println("new AVReceive2(sessions)");
		
		if (!avReceive.initialize()) 
		{
			System.err.println("Failed to initialize the sessions.");
			System.exit(-1);
		}
		System.out.println("avReceive.initialize()");

		// Check to see if AVReceive2 is done.
		try 
		{
			while (!avReceive.isDone())
			Thread.sleep(1000);
		} 
		catch (Exception e) 
		{}

		System.err.println("Exiting AVReceive2");
	
	}
	

}
